package com.zxy.supplier_system.server.service

import com.zxy.supplier_system.server.controller.MarketsGoodsController
import com.zxy.supplier_system.server.entity.Employee
import com.zxy.supplier_system.server.entity.Market
import com.zxy.supplier_system.server.entity.MarketGoods
import com.zxy.supplier_system.server.repository.*
import com.zxy.supplier_system.server.utils.IntIdAndName
import com.zxy.supplier_system.server.utils.joinOnce
import com.zxy.supplier_system.server.utils.setCellValues
import com.zxy.supplier_system.server.utils.toIntIdAndName
import org.apache.poi.ss.usermodel.WorkbookFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.core.io.InputStreamResource
import org.springframework.core.io.Resource
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.domain.Specification
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream


@Service
class MarketGoodsService(
    private val marketGoodsRepository: MarketGoodsRepository,
    private val employeeService: EmployeeService,
    private val goodsBrandRepository: GoodsBrandRepository,
    private val goodsCategoryRepository: GoodsCategoryRepository,
    private val factoryRepository: FactoryRepository,
    @Value("classpath:excel/templates/导出门店商品模板.xlsx")
    private val resource: Resource
) {
    fun queryMarketsGoods(
        marketId: Int,
        request: MarketsGoodsController.QueryMarketGoodsRequest,
        pageable: Pageable
    ): Page<MarketsGoodsController.QueryMarketsGoodsResponse> {
        val employee = employeeService.getRequiredCurrentEmployee()
        return marketGoodsRepository.findAll(
            specificationByQueryMarketGoodsRequest(marketId, employee, request), pageable
        ).map {
            MarketsGoodsController.QueryMarketsGoodsResponse(
                amountInMarket = it.amount,
                amount = it.goods.amount,
                id = it.goods.id,
                name = it.goods.name,
                price = it.goods.price,
                barcode = it.goods.barcode,
            )
        }
    }

    fun getAllMarketGoodsBrands(marketId: Int): List<IntIdAndName> {
        return this.goodsBrandRepository.findAll(GoodsBrandRepository.Specifications.inMarketGoods(marketId)).map {
            it.toIntIdAndName()
        }
    }

    fun getAllMarketGoodsCategories(marketId: Int): List<IntIdAndName> {
        return this.goodsCategoryRepository.findAll(GoodsCategoryRepository.Specifications.inMarketGoods(marketId))
            .map {
                it.toIntIdAndName()
            }
    }

    fun getAllMarketGoodsFactories(marketId: Int): List<IntIdAndName> {
        return this.factoryRepository.findAll(FactoryRepository.Specifications.inMarketGoods(marketId)).map {
            it.toIntIdAndName()
        }
    }

    @Transactional
    fun exportMarketsGoodsToExcel(
        marketId: Int,
        request: MarketsGoodsController.QueryMarketGoodsRequest
    ): InputStreamResource {
        val employee = employeeService.getRequiredCurrentEmployee()
        val marketGoodsList = marketGoodsRepository.findAll(
            specificationByQueryMarketGoodsRequest(marketId, employee, request)
        )
        val workbook = WorkbookFactory.create(resource.inputStream)
        val sheet = workbook.getSheetAt(0)
        marketGoodsList.forEachIndexed { index, marketGoods ->
            val row = sheet.createRow(index + 1)
            val goods = marketGoods.goods
            row.setCellValues(
                arrayListOf(
                    goods.barcode,
                    goods.name,
                    marketGoods.amount.toDouble(),
                    goods.brand?.name,
                    goods.category?.name,
                    goods.factory?.name,
                    goods.amount,
                    goods.price,
                    goods.boxSpecification,
                )
            )
        }
        val out = ByteArrayOutputStream()
        workbook.write(out)
        return InputStreamResource(ByteArrayInputStream(out.toByteArray()))
    }

    private fun specificationByQueryMarketGoodsRequest(
        marketId: Int,
        employee: Employee,
        request: MarketsGoodsController.QueryMarketGoodsRequest
    ): Specification<MarketGoods> =
        Specification.allOf(
            MarketGoodsRepository.Specifications.marketIdEqual(
                marketId
            ),
            MarketGoodsRepository.Specifications.ifUCanSee(employee),
            MarketGoodsRepository.Specifications.byCondition(request),
            SystemServiceRepository.Specifications.systemServiceEquals({ root ->
                root.joinOnce<MarketGoods, Market>(
                    "market"
                )
            }, employee.systemService),
        )

}
